// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-8-24

#ifndef __SOCKBASE_H__
#define __SOCKBASE_H__

#pragma once

#include "refdata.h"
#include "singlelist.h"

class CJoySockData;
class CJoySockBase;

//##ModelId=44CF1757008F
enum JoySockBlockingMode
{
	//##ModelId=44CF1757009C
    SBM_None,
	//##ModelId=44CF1757009D
    SBM_Blocking,
	//##ModelId=44CF1757009E
    SBM_Threading,
};

#pragma pack(push, 1)

//##ModelId=44CF175700AB
class CJoySockSendData : public CJoyRefData
{
protected:
	//##ModelId=44CF175700DA
    template<typename T> friend void JoyConstruct(T*);
	//##ModelId=44CF175700AD
    CJoySockSendData() {}
public:
	//##ModelId=44CF175700AE
    int m_size;
	//##ModelId=44CF175700AF
    void* GetData()
    {
        return this+1;
    }
	//##ModelId=44CF175700BB
    int GetDataSize() const
    {
        return m_size;
    }
	//##ModelId=44CF175700BD
    void* GetBlock()
    {
        return &m_size;
    }
	//##ModelId=44CF175700BE
    int GetBlockSize() const
    {
        return m_size + sizeof(m_size);
    }
	//##ModelId=44CF175700C0
    static CJoySockSendData* Create(int nSize);
	//##ModelId=44CF175700CB
    static CJoySockSendData* Create(const void* pBuf, int nSize);
};

//##ModelId=44CF175700DD
class CJoySockRecvData
{
public:
	//##ModelId=44CF175700ED
    CJoySockRecvData*   m_next;
	//##ModelId=44CF175700F0
    CJoySockData*   m_sockData;
	//##ModelId=44CF175700FB
    sockaddr_in m_from;
	//##ModelId=44CF175700FF
    int m_size;

	//##ModelId=44CF17570100
    ~CJoySockRecvData();
	//##ModelId=44CF17570109
    void* GetData()
    {
        return this+1;
    }
	//##ModelId=44CF1757010A
    int GetDataSize() const
    {
        return m_size;
    }
	//##ModelId=44CF1757010C
    static CJoySockRecvData* Create(CJoySockData* sockData, int nSize);
	//##ModelId=44CF1757011A
    static CJoySockRecvData* Create(CJoySockData* sockData, const void* pBuf, int nSize);
};

#pragma pack(pop)

//##ModelId=44CF17570148
class CJoySockData : public CJoyRefData
{
public:
	//##ModelId=44CF17570225
    class CSendItem
    {
    public:
		//##ModelId=44CF17570235
        CSendItem*  m_next;
		//##ModelId=44CF17570238
        CJoySockSendData*   m_data;
		//##ModelId=44CF17570243
        sockaddr_in m_addr;
		//##ModelId=44CF17570247
        CSendItem()
            : m_next(NULL), m_data(NULL)
        {
        }
		//##ModelId=44CF17570248
        ~CSendItem()
        {
            if(m_data != NULL)
            {
                m_data->Release();
            }
        }
    };
	//##ModelId=44CF17570249
    typedef CJoySingleList<CSendItem>   CSendList;

	//##ModelId=44CF1757014B
    SOCKET  m_hSocket;

	//##ModelId=44CF17570157
    HANDLE      m_hRecvThread;
	//##ModelId=44CF17570158
    HANDLE      m_hSendThread;
	//##ModelId=44CF17570159
    HANDLE      m_hSendEvent;
	//##ModelId=44CF1757015B
    CSendList   m_sendList;
	//##ModelId=44CF17570168
    CJoyCriticalSection m_sendingLock;
	//##ModelId=44CF1757016D
    CJoyCriticalSection m_sendLock;
	//##ModelId=44CF17570178
    volatile CJoySockBase*   m_owner;

	//##ModelId=44CF1757017C
    volatile bool    m_bCancelSend;
	//##ModelId=44CF1757017D
    volatile bool    m_bClose;
	//##ModelId=44CF1757017E
    volatile bool    m_bConnected;
	//##ModelId=44CF17570186
    bool    m_bStream;
	//##ModelId=44CF17570187
    bool    m_bBlock;
	//##ModelId=44CF17570188
    bool    m_bBlocking;

	//##ModelId=44CF17570196
    CJoySockData();
	//##ModelId=44CF17570197
    virtual ~CJoySockData();

	//##ModelId=44CF17570199
    CSendItem* PeekSendItem();

	//##ModelId=44CF175701A5
    virtual void PostRecvData(CJoySockRecvData* pData);
	//##ModelId=44CF175701A8
    virtual void PostSendItem(CSendItem* pItem);

	//##ModelId=44CF175701AB
    virtual void PostClose();

	//##ModelId=44CF175701B6
    void CreateThreads(int type, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44CF175701C5
    void ResumeThreads();
	//##ModelId=44CF175701C6
    void CloseThreads();
	//##ModelId=44CF175701C7
    void Attach(SOCKET s, bool bSend = true, bool bRecv = true, bool bBlock = true);

	//##ModelId=44CF175701D5
    bool Send(CJoySockSendData* pData, JoySockBlockingMode bm = SBM_None);
	//##ModelId=44CF175701E4
    bool Send(const void* buf, int size, JoySockBlockingMode bm = SBM_None);
	//##ModelId=44CF175701E8
    bool SendTo(const sockaddr_in& addr, CJoySockSendData* pData);
	//##ModelId=44CF175701F6
    bool SendTo(const sockaddr_in& addr, const void* buf, int size);

	//##ModelId=44CF17570204
    virtual CJoySockData* CreateData(int type, const sockaddr_in& addr, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44CF17570215
    virtual CJoySockData* CreateData(SOCKET s, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44CF17570223
    virtual CJoySockData* OnCreateData();
};

//##ModelId=44CF17570271
class CJoySockBase
{
protected:
    friend class CJoySocketTool;

	//##ModelId=44CF17570273
    CJoySockData*   m_data;
	//##ModelId=44CF17570280
    HANDLE  m_hConnectThread;

	//##ModelId=44CF17570281
    virtual void OnRecvData(CJoySockRecvData& data);
	//##ModelId=44CF17570284
    virtual void OnClose();
	//##ModelId=44CF17570290
    virtual void OnConnect(int err);
	//##ModelId=44CF17570293
    virtual void OnAttach(CJoySockData* pData);
	//##ModelId=44CF17570296
    virtual CJoySockData* OnCreateData();

public:
	//##ModelId=44CF17570298
    CJoySockBase(void);
	//##ModelId=44CF1757029F
    virtual ~CJoySockBase(void);

	//##ModelId=44CF175702A2
    void Attach(CJoySockData* pData);
	//##ModelId=44CF175702A4
    void SetData(CJoySockData* pData);
	//##ModelId=44CF175702A6
    bool Create(int type, const sockaddr_in& addr, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44CF175702B3
    bool Create(int nType, int nPort);
	//##ModelId=44CF175702C0
    bool Connect(const sockaddr_in& addr);
	//##ModelId=44CF175702C2
    bool Connect(PCSTR pszIP, int nPort);

	//##ModelId=44CF175702C5
    CJoySockData* CreateData(int type, const sockaddr_in& addr, bool bSend = true, bool bRecv = true, bool bBlock = true);
	//##ModelId=44CF175702D1
    CJoySockData* CreateData(SOCKET s, bool bSend = true, bool bRecv = true, bool bBlock = true);

	//##ModelId=44CF175702DE
    virtual void Close();

	//##ModelId=44CF175702E0
    int GetLastError() const
    {
        int e = WSAGetLastError();
        return e;
    }
	//##ModelId=44CF175702E2
    CJoySockData* GetSockData() const
    {
        return m_data;
    }

    //static CString AddressToString(const sockaddr_in& addr);
	//##ModelId=44CF175702E4
    static void MakeAddress(sockaddr_in& addr, PCSTR pszIP, int nPort);

	//##ModelId=44CF175702EE
    bool Send(CJoySockSendData* pData);
	//##ModelId=44CF175702F0
    bool Send(const void* buf, int size);
	//##ModelId=44CF175702F3
    bool SendTo(const sockaddr_in& addr, CJoySockSendData* pData);
	//##ModelId=44CF175702F6
    bool SendTo(const sockaddr_in& addr, const void* buf, int size);

	//##ModelId=44CF17570300
    void SetNoTcpDelay(bool bNoDelay);
};

#endif  // __SOCKBASE_H__
